﻿using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using MimeKit;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace Sgr.Email
{
    /// <summary>
    /// 基于 MailKit 的 SMTP 邮件服务实现
    /// </summary>
    public class SmtpService : ISmtpService
    {
        // 邮件地址分隔符
        private static readonly char[] EmailsSeparator = new[] { ',', ';' };

        private readonly ILogger<SmtpService> _logger;

        /// <summary>
        /// 初始化 SMTP 邮件服务
        /// </summary>
        /// <param name="logger">日志服务</param>
        public SmtpService(ILogger<SmtpService> logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="smtpInfo"></param>
        /// <param name="message"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<SmtpResult> SendAsync(
            SmtpInfo smtpInfo,
            MailMessage message,
            CancellationToken cancellationToken = default)
        {
            Check.NotNull(smtpInfo, nameof(smtpInfo));
            Check.NotNull(message, nameof(message));

            try
            {
                // 转换为 MimeMessage
                var mimeMessage = CreateMimeMessage(smtpInfo, message);

                // 发送邮件
                await SendWithSmtpClientAsync(
                    smtpInfo,
                    mimeMessage,
                    cancellationToken);

                _logger.LogInformation(
                    "邮件发送成功: From={From}, To={To}, Subject={Subject}",
                    smtpInfo.From,
                    message.To,
                    message.Subject);

                return SmtpResult.Success;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                    "邮件发送失败: From={From}, To={To}, Subject={Subject}",
                    smtpInfo.From,
                    message.To,
                    message.Subject);

                return SmtpResult.Failed($"An error occurred while sending an email: '{ex.Message}'");
            }
        }

        /// <summary>
        /// 创建 MimeMessage 邮件消息
        /// </summary>
        private static MimeMessage CreateMimeMessage(SmtpInfo smtpInfo, MailMessage message)
        {
            var mimeMessage = new MimeMessage
            {
                // 设置发件人信息
                Sender = new MailboxAddress(smtpInfo.Sender, smtpInfo.From)
            };
            mimeMessage.From.Add(new MailboxAddress(smtpInfo.Sender, smtpInfo.From));

            // 添加收件人
            AddRecipients(mimeMessage.To, message.To);

            // 添加抄送
            AddRecipients(mimeMessage.Cc, message.Cc);

            // 添加密送
            AddRecipients(mimeMessage.Bcc, message.Bcc);

            // 设置回复地址
            foreach (var address in mimeMessage.From)
            {
                mimeMessage.ReplyTo.Add(address);
            }

            // 设置邮件主题
            mimeMessage.Subject = message.Subject;

            // 构建邮件正文
            var bodyBuilder = new BodyBuilder();
            if (message.IsBodyHtml)
            {
                bodyBuilder.HtmlBody = message.Body;
            }
            if (message.IsBodyText)
            {
                bodyBuilder.TextBody = message.BodyText;
            }

            // 添加附件
            foreach (var attachment in message.Attachments)
            {
                if (attachment.Stream != null)
                {
                    bodyBuilder.Attachments.Add(attachment.Filename, attachment.Stream);
                }
            }

            mimeMessage.Body = bodyBuilder.ToMessageBody();
            return mimeMessage;
        }

        /// <summary>
        /// 添加收件人地址
        /// </summary>
        private static void AddRecipients(InternetAddressList addressList, string? recipients)
        {
            if (string.IsNullOrWhiteSpace(recipients)) return;

            foreach (var address in recipients.Split(EmailsSeparator, StringSplitOptions.RemoveEmptyEntries))
            {
                addressList.Add(MailboxAddress.Parse(address.Trim()));
            }
        }

        /// <summary>
        /// 使用 SMTP 客户端发送邮件
        /// </summary>
        private async Task SendWithSmtpClientAsync(
            SmtpInfo smtpInfo,
            MimeMessage message,
            CancellationToken cancellationToken)
        {
            // 获取安全套接字选项
            var secureSocketOptions = GetSecureSocketOptions(smtpInfo.VerificationType);

            using var client = new SmtpClient();
            try
            {
                // 配置客户端
                client.Timeout = smtpInfo.TimeoutSeconds * 1000;
                // 根据配置决定是否验证证书
                if (smtpInfo.ValidateServerCertificate)
                {
                    // 使用严格的证书验证
                    client.ServerCertificateValidationCallback = ValidateServerCertificateStrict;
                }
                else
                {
                    // 跳过证书验证
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                }

                // 连接服务器
                await client.ConnectAsync(
                    smtpInfo.Host,
                    smtpInfo.Port,
                    secureSocketOptions,
                    cancellationToken);

                // 身份认证
                await AuthenticateByTypeAsync(client, smtpInfo, cancellationToken);

                // 发送邮件
                await client.SendAsync(message, cancellationToken);
            }
            finally
            {
                // 确保断开连接
                if (client.IsConnected)
                {
                    await client.DisconnectAsync(true, cancellationToken);
                }
            }
        }

        /// <summary>
        /// 根据认证类型执行认证
        /// </summary>
        private static async Task AuthenticateByTypeAsync(
            SmtpClient client,
            SmtpInfo smtpInfo,
            CancellationToken cancellationToken)
        {
            switch (smtpInfo.AuthenticationType)
            {
                case SmtpAuthenticationType.Basic:
                    // 基本认证：直接使用用户名和密码
                    await client.AuthenticateAsync(
                        smtpInfo.UserName,
                        smtpInfo.Password,
                        cancellationToken);
                    break;

                case SmtpAuthenticationType.AuthCode:
                    // 授权码认证：使用NetworkCredential
                    var credentials = new NetworkCredential(
                        smtpInfo.UserName,
                        smtpInfo.Password);
                    await client.AuthenticateAsync(credentials, cancellationToken);
                    break;

                case SmtpAuthenticationType.OAuth2:
                    // OAuth2认证：使用SASL机制
                    var oauth2 = new SaslMechanismOAuth2(
                        smtpInfo.UserName,
                        smtpInfo.Password); // Password字段存储访问令牌
                    await client.AuthenticateAsync(oauth2, cancellationToken);
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// 获取安全套接字选项
        /// </summary>
        private static SecureSocketOptions GetSecureSocketOptions(string verificationType)
            => verificationType.ToUpperInvariant() switch
            {
                "NULL" => SecureSocketOptions.None,
                "SSL" => SecureSocketOptions.SslOnConnect,
                "TLS" => SecureSocketOptions.StartTls,
                _ => SecureSocketOptions.Auto
            };

        /// <summary>
        /// 严格验证服务器证书
        /// </summary>
        private bool ValidateServerCertificateStrict(
            object sender,
            X509Certificate? certificate,
            X509Chain? chain,
            SslPolicyErrors sslPolicyErrors)
        {
            // 如果没有策略错误，验证通过
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;

            // 记录证书错误信息
            _logger.LogError(
                "SMTP服务器证书验证失败: 主题={Subject}, 颁发者={Issuer}, " +
                "指纹={Thumbprint}, 过期时间={ExpirationDate}, 策略错误={PolicyErrors}",
                certificate?.Subject,
                certificate?.Issuer,
                certificate?.GetCertHashString(),
                certificate?.GetExpirationDateString(),
                sslPolicyErrors);

            // 记录证书链错误
            if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)
                && chain?.ChainStatus != null)
            {
                foreach (var status in chain.ChainStatus)
                {
                    _logger.LogError(
                        "证书链状态: {Status} - {Information}",
                        status.Status,
                        status.StatusInformation);
                }
            }

            // 验证失败
            return false;
        }
    }
}